package com.gitee.wsl.compose.chart.xy.axis.model

import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import com.gitee.wsl.compose.chart.xy.axis.AxisModel
import com.gitee.wsl.compose.chart.xy.axis.AxisState
import com.gitee.wsl.compose.chart.xy.axis.AxisStateImp
import com.gitee.wsl.compose.chart.xy.axis.TickValues
import com.gitee.wsl.compose.chart.xy.axis.TickValuesImp
import com.gitee.wsl.mathematics.function.scale.Scale
import com.gitee.wsl.mathematics.function.scale.continuous.linear.LinearScale

interface ScaleAxisModel<T,D,SCALE: Scale<D, T>> : AxisModel<T> where T : Comparable<T>, T : Number {
    val scale: SCALE
}

open class AbstractScaleAxisModel<T>(
                                     override val scale: LinearScale<T>,
                                     val minimumMajorTickSpacing: Dp= 50.dp,
                                     private val zoomRangeLimit: Long ,
                                     private val minimumMajorTickIncrement: Long,
                                     private val minorTickCount: Int = 4,
                                     private val allowZooming: Boolean = true,
                                     private val allowPanning: Boolean = true,
): ScaleAxisModel<T, Double, LinearScale<T>> where T : Comparable<T>, T : Number{
    override fun computeTickValues(axisLength: Dp): TickValues<T> {
        val minTickSpacing = (minimumMajorTickSpacing / axisLength).coerceIn(0f..1f)
        val count = axisLength / minTickSpacing
        val ticks = scale.ticks(count.value.toInt())
        val ticksValues = ticks.map { scale(it) }
        return TickValuesImp(majorTickValues = ticksValues)
    }

    override fun computeOffset(point: T): Float {
        return scale.invert(point).toFloat()
    }

    override fun compute(axisLength: Dp): Pair<AxisState, TickValues<T>> {
        val minTickSpacing = (minimumMajorTickSpacing / axisLength).coerceIn(0f..1f)
        val count = axisLength / minTickSpacing
        val ticks = scale.ticks(count.value.toInt())
        val ticksValues = ticks.map { scale(it) }
        return AxisStateImp(majorTickOffsets = ticks.map { it.toFloat() }) to TickValuesImp(majorTickValues = ticksValues)
    }

}